package com.godenwater.recv.handler;

import java.text.SimpleDateFormat;
import java.util.Arrays;

import com.godenwater.recv.model.CommonMessage;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.gov.mwr.szy206.SzyBuilder;
import cn.gov.mwr.szy206.SzyMessageBody;
import cn.gov.mwr.szy206.SzyMessageHeader;
import cn.gov.mwr.szy206.SzyParser;
import cn.gov.mwr.szy206.body.Body02H;
import cn.gov.mwr.szy206.body.BodyDown;
import cn.gov.mwr.szy206.utils.ByteUtil;
import cn.gov.mwr.szy206.utils.CrcUtil;

import com.godenwater.recv.RecvConstant;
import com.godenwater.recv.server.all.RtuServer;

public class Szy206MessageHandler extends AbstractHandler {

    private static Logger logger = LoggerFactory
            .getLogger(Szy206MessageHandler.class);

    private SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");

    /**
     * Returns a singleton UserManager instance.
     *
     * @return a UserManager instance.
     */
    public static Szy206MessageHandler getInstance() {
        return Szy206MessageHandlerContainer.instance;
    }

    // Wrap this guy up so we can mock out the UserManager class.
    private static class Szy206MessageHandlerContainer {
        private static Szy206MessageHandler instance = new Szy206MessageHandler();
    }

    private Szy206MessageHandler() {
    }

    public void perform(String channel, IoSession session,
                        CommonMessage message, int recvPort) {

        byte[] bytes = message.getContent();

        // 1.1：解析控制域C
        logger.info("====================解析【水资源】报文数据=======================");
        logger.info(">> 报文内容：" + ByteUtil.toHexString(bytes));

        int pos = 0;
        byte control = bytes[0];
        int[] C = SzyParser.parseControl(control);
        // System.out.println(">> 控制域：" + (C[0] == 1 ? "上行" : "下行") + " \t"
        // + (C[1] == 0 ? "单帧" : "多帧") + " \t" + " 传输" + C[2] + " "
        // + SzyConst.FUNC[C[3]]);
        pos = pos + 1;

        int serial = 1;
        if (C[1] == 1) {
            byte serialByte = bytes[1];
            serial = ByteUtil.bytesToUbyte(new byte[]{serialByte});
            pos = pos + 1;
        }

        // 1.2：解析地址域A
        byte[] address = new byte[5];
        System.arraycopy(bytes, pos, address, 0, address.length);

        // 1.3：解析AFN
        byte[] AFN = new byte[1];
        System.arraycopy(bytes, pos, AFN, 0, AFN.length);

        String stcd = SzyParser.parseStcd(address);

        // ------------------------------------------------------------
        // 1、 校验消息
        boolean crcFlag = checkCRC(message);// 校验消息体，CRC校验

        // 2、 存放于消息队列中，等待处理。将队列放在此处，减少了对链接报的处理
        // 2、将消息存放在日志文件中 2016-10-18
        /**
         ChannelMessage cm = new ChannelMessage();
         cm.setChannel(channel);
         cm.setMessage(message);
         cm.setCrcFlag(crcFlag);
         // server.queuePush(cm);
         RtuServer.getInstance().getMessageManager().append(Constant.SZY206, cm);
         */

        // 3、应答回复或重发报文请求
        byte[] replyMsg = null;
        if (crcFlag) {
            // 确认应答
            logger.info("校验结果，报文CRC验证<相一致>，M2模式发送\"应答\"回复....");
            replyMsg = replyMessage(session, message);
        } else {
            // 重发请求
            logger.info("校验结果，报文CRC验证\"不一致 \"，M2模式发送\"重发\"请求....");
            replyMsg = repeatMessage(message);
        }

        if (replyMsg != null
                && (channel.equalsIgnoreCase("GPRS") || channel
                .equalsIgnoreCase("UDP"))) {
            logger.info("回复报文，" + ByteUtil.toHexString(replyMsg) + "");
            session.write(replyMsg);
        }

        // 4、将测站与session关联起来
        RtuServer.getInstance().getSessionManager().bindSession(session, RecvConstant.SZY206, stcd);

        // 5、追加畅通率计算
        rateMessage(channel, AFN[0], stcd);

        // 6、监测器显示
        String logMsg = viewMessage(message);
        monitorMessage(channel, stcd, logMsg);

        // 2.2 写入报文记录
        saveMessage(channel, RecvConstant.SZY206, stcd, crcFlag, logMsg, "0", "", "", 0, "", 0);
    }

    public boolean checkCRC(CommonMessage message) {

        logger.info("校验<水资源>报文， 开始校验CRC...  ");

        byte[] bytes = message.getContent();

        byte[] crcResult = CrcUtil.crc8Check(bytes);

        // System.out.println(">> crcResult " +
        // ByteUtil.toHexString(crcResult));

        if (Arrays.equals(crcResult, message.getCRC())) {
            return true;
        } else {
            return false;
        }
    }

    public byte[] replyMessage(IoSession session, CommonMessage message) {

        byte[] bytes = message.getContent();
        System.out.println(">> 报文长度： " + bytes.length);

        int pos = 0;
        byte control = bytes[0];
        int[] C = SzyParser.parseControl(control);
        // System.out.println(">> 控制域：" + (C[0] == 1 ? "上行" : "下行") + " \t"
        // + (C[1] == 0 ? "单帧" : "多帧") + " \t" + " 传输" + C[2] + " "
        // + SzyConst.FUNC[C[3]]);
        pos = pos + 1;

        int serial = 1;
        if (C[1] == 1) {
            byte serialByte = bytes[1];
            serial = ByteUtil.bytesToUbyte(new byte[]{serialByte});
            pos = pos + 1;
        }

        // 1.2：解析地址域A
        byte[] address = new byte[5];
        System.arraycopy(bytes, pos, address, 0, address.length);
        // String stcd = SzyParser.parseAddress(address);
        pos = pos + 5;

        // 1.3：解析AFN
        byte[] AFN = new byte[1];
        System.arraycopy(bytes, pos, AFN, 0, AFN.length);

        byte newcontrol = SzyBuilder.newControl(0, 0, C[2], 0);
        Body02H body = new Body02H();
        body.setData(AFN);

        SzyMessageBody msgBody = new SzyMessageBody();
        msgBody.setControl(newcontrol);
        msgBody.setAddress(address);
        msgBody.setUserData(body);

        switch (AFN[0]) {
            case (byte) 0x02:// 由中心站下发的报文，收到后的报文不进行回复
                break;
            case (byte) 0x81:// 进行回复
            case (byte) 0x82:
            case (byte) 0xC0:

                // replyMsg = replyMessage(address, C[2], mode);
                break;
            default:

        }

        return SzyBuilder.toByte(SzyBuilder.newMessage(msgBody));
    }

    public byte[] repeatMessage(CommonMessage message) {
        // byte[] address, int FCB, int FUNC
        byte[] bytes = message.getContent();
        System.out.println(">> 报文长度： " + bytes.length);

        int pos = 0;
        byte control = bytes[0];
        int[] C = SzyParser.parseControl(control);
        // System.out.println(">> 控制域：" + (C[0] == 1 ? "上行" : "下行") + " \t"
        // + (C[1] == 0 ? "单帧" : "多帧") + " \t" + " 传输" + C[2] + " "
        // + SzyConst.FUNC[C[3]]);
        pos = pos + 1;

        int serial = 1;
        if (C[1] == 1) {
            byte serialByte = bytes[1];
            serial = ByteUtil.bytesToUbyte(new byte[]{serialByte});
            pos = pos + 1;
        }

        // 1.2：解析地址域A
        byte[] address = new byte[5];
        System.arraycopy(bytes, pos, address, 0, address.length);
        // String stcd = SzyParser.parseAddress(address);
        pos = pos + 5;

        byte ncontrol = SzyBuilder.newControl(0, 0, C[2], C[3]);

        BodyDown body = new BodyDown();
        // body.setAFN(afn);
        // body.setData(data);

        SzyMessageBody msgBody = new SzyMessageBody();
        msgBody.setControl(ncontrol);
        msgBody.setAddress(address);
        msgBody.setUserData(body);

        return SzyBuilder.toByte(SzyBuilder.newMessage(msgBody));
    }

    /**
     * 计算畅通率
     *
     * @param message
     * @return
     */
    public void rateMessage(String channel, byte afn, String stcd) {

        // -----------------水资源通信规约畅通率计算---------------------------
        // ----------添加畅通率计算 ,根据自报实时数据AFN=C0h进行计算-----------------

        try {
            if (afn == (byte) 0xC0) {
                //RtuServer.getInstance().getStationManager()
                //		.updateRate(channel, stcd);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // -----------------------------------------------------------

    }

    /**
     * 将报文转换为HEX字符串
     *
     * @param message
     * @return
     */
    public String viewMessage(CommonMessage message) {

        SzyMessageHeader header = (SzyMessageHeader) message.getHeader();
        byte[] bytes = message.getContent();

        int pos = 0;
        byte control = bytes[0];
        int[] C = SzyParser.parseControl(control);
        pos = pos + 1;

        int serial = 1;
        if (C[1] == 1) {
            byte serialByte = bytes[1];
            serial = ByteUtil.bytesToUbyte(new byte[]{serialByte});
            pos = pos + 1;
        }

        // 1.2：解析地址域A
        byte[] address = new byte[5];
        System.arraycopy(bytes, pos, address, 0, address.length);

        String log = ByteUtil.toHexString(header.getStartBit())
                + ByteUtil.toHexString(header.getBodySize())
                + ByteUtil.toHexString(header.getBodyStartBit())
                + ByteUtil.toHexString(bytes)
                + ByteUtil.toHexString(message.getCRC())
                + ByteUtil.toHexString(message.getEof());

        return log;
    }

}
